package edu.cmu.cs211.bacon.tests;

import static org.junit.Assert.*;

import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.junit.Test;


import edu.cmu.cs211.bacon.util.Edge;
import edu.cmu.cs211.bacon.util.GeneralGraph;

public class GraphTest {
	@Test (expected = NullPointerException.class)
	public void testNullEdge	()
	{
		GeneralGraph<String,Edge<String>> g = new GeneralGraph<String,Edge<String>>();
		g.addEdge(null);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void testInvalidEdge	()
	{
		GeneralGraph<String,Edge<String>> g = new GeneralGraph<String,Edge<String>>();
		g.addEdge(new Edge<String>("1", "1", 1));
	}
	
	@Test
	public void testNeighbors()
	{
		GeneralGraph<String,Edge<String>> g = new GeneralGraph<String,Edge<String>>();
		g.addVertex("a");
		g.addVertex("b");
		g.addVertex("c");
		g.addEdge(new Edge<String>("a", "b", 1));
		g.addEdge(new Edge<String>("a", "c", 1));
		g.addEdge(new Edge<String>("b", "c", 1));
		
		assertEquals("number of vertex a's edges",g.neighbors("a").size(),2);
		assertEquals("number of vertex a's edges",g.neighbors("c").size(),0);
		
		g.addEdge(new Edge<String>("c", "a", 1));
		assertEquals("number of vertex a's edges",g.neighbors("c").size(),1);
	}
	@Test 
	public void testRemoveEdge	()
	{
		GeneralGraph<String,Edge<String>> g = new GeneralGraph<String,Edge<String>>();
		g.addVertex("a");
		g.addVertex("b");
		g.addEdge(new Edge<String>("a", "b", 1));
		g.removeEdge("a", "b");
		assertEquals("there should be no edge",g.connected("a", "b"),null);
	}
	
	@Test
	public void testOutgoingEdge()
	{
		GeneralGraph<String,Edge<String>> g = new GeneralGraph<String,Edge<String>>();
		g.addVertex("a");
		g.addVertex("b");
		g.addVertex("c");
		g.addEdge(new Edge<String>("a", "b", 1));
		g.addEdge(new Edge<String>("a", "c", 1));
		assertEquals("neighbors of 1",g.outgoingEdges("a").size(),2);
	}
	@Test
	public void createTest ()
	{
		GeneralGraph<String,Edge<String>> g = new GeneralGraph<String,Edge<String>>();
		assertEquals("Empty graph should have no vertices",0, g.vertices().size());
		//add in two vertex
		g.addVertex("1");
		g.addVertex("2");
		//add in new edges
		Edge<String> e = new Edge<String>("1","2",1);
		g.addEdge(e);
		//create a new collection that contain vertex 2
		Set<String> res = new HashSet<String>();
		//create a new arraylist that contain all the edges
		List<Edge<String>> edges = new ArrayList<Edge<String>>();
		edges.add(e);
		res.add("2");
		assertEquals("neighbors of 1",g.neighbors("1"),res);
		assertEquals("outgoing edges",g.outgoingEdges("1").size(),1);
		assertEquals("connected",g.connected("1", "2"),e);
		assertEquals("add existing edges",g.addEdge(e),false);
		//add in 1 to contain all the vertices
		res.add("1");
		assertEquals("vertices",g.vertices(),res);
		//a copy of the current graph g
		GeneralGraph<String,Edge<String>> g1 = new GeneralGraph<String,Edge<String>>(g);
		assertEquals("the copied graph",g1.vertices().equals(g.vertices()),true);
		g.clearEdges();

		assertEquals("clear edge should not affect vertices",g1.vertices().equals(g.vertices()),true);
		assertEquals("their neighbors should be the same",g1.neighbors("1").equals(g.neighbors("1")),false);
		GeneralGraph<String,Edge<String>> g2 = new GeneralGraph<String,Edge<String>>(res,edges);
		//try to use another constructor see if it works
		assertEquals("the copied graph",g1.vertices().equals(g2.vertices()),true);
	}
	
	/*
	 * continuously adds new vertices into graph,
	 * check size consistency
	 */
	@Test
	public void stressTest()
	{
		GeneralGraph<Integer, Edge<Integer>> g = new GeneralGraph<Integer, Edge<Integer>>();
		int size = 0;
		Random r      = new Random();
	    int    NITERS = 10000;
	    
	    for( int i = 0; i < NITERS; ++i )
	    {
	      //Create vertex to be add
	      Integer v = Integer.valueOf(r.nextInt(100));
	     
	      if( r.nextFloat() < 0.66f )
	      {
	    	  if (g.addVertex(v))
	    		  size++;
	      }

	      //Make sure the size is always consistent
	      assertEquals("the size of vertices size",g.vertices().size(),size);
	    }
	}

}
